"""
EDA分析API路由模块
提供EDA数据分析相关的API接口，包括文件上传、批量分析、结果导出等功能

作者: Python开发工程师
创建时间: 2024年
"""

import os
import json
import uuid
import logging
import traceback
import math
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Any, Optional

import pandas as pd
from flask import Blueprint, request, jsonify, send_file, current_app
from werkzeug.utils import secure_filename
from werkzeug.datastructures import FileStorage

# 导入EDA处理器
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src'))
from eda_processor import EDAProcessor
import numpy as np

# 创建蓝图
eda_bp = Blueprint('eda_analysis', __name__, url_prefix='/eda')

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 配置常量
ALLOWED_EXTENSIONS = {'txt', 'csv'}
MAX_FILE_SIZE = 50 * 1024 * 1024  # 50MB
UPLOAD_FOLDER = Path('uploads')
OUTPUT_FOLDER = Path('output')

# 确保目录存在
UPLOAD_FOLDER.mkdir(exist_ok=True)
OUTPUT_FOLDER.mkdir(exist_ok=True)

# 全局存储分析任务状态
analysis_tasks = {}

# 任务状态持久化文件路径
TASKS_STATE_FILE = Path('tasks_state.json')

def save_tasks_state():
    """保存任务状态到文件"""
    try:
        with open(TASKS_STATE_FILE, 'w', encoding='utf-8') as f:
            json.dump(analysis_tasks, f, ensure_ascii=False, indent=2)
        logger.debug(f"任务状态已保存到 {TASKS_STATE_FILE}")
    except Exception as e:
        logger.error(f"保存任务状态失败: {str(e)}")

def load_tasks_state():
    """从文件加载任务状态"""
    global analysis_tasks
    try:
        if TASKS_STATE_FILE.exists():
            with open(TASKS_STATE_FILE, 'r', encoding='utf-8') as f:
                analysis_tasks = json.load(f)
            logger.info(f"已从 {TASKS_STATE_FILE} 加载 {len(analysis_tasks)} 个任务")
        else:
            logger.info("任务状态文件不存在，使用空任务列表")
    except Exception as e:
        logger.error(f"加载任务状态失败: {str(e)}")
        analysis_tasks = {}

def recover_tasks_from_uploads():
    """从uploads目录恢复任务状态"""
    try:
        recovered_count = 0
        for task_dir in UPLOAD_FOLDER.iterdir():
            if task_dir.is_dir() and task_dir.name not in analysis_tasks:
                task_id = task_dir.name
                
                # 检查目录中是否有文件
                files = []
                for file_path in task_dir.iterdir():
                    if file_path.is_file():
                        files.append({
                            'name': file_path.name,
                            'size': file_path.stat().st_size,
                            'path': str(file_path),
                            'status': 'uploaded'
                        })
                
                if files:  # 只有当目录中有文件时才恢复任务
                    analysis_tasks[task_id] = {
                        'task_id': task_id,
                        'status': 'uploaded',
                        'files': files,
                        'created_at': datetime.now().isoformat(),
                        'progress': 0,
                        'results': [],
                        'recovered': True  # 标记为恢复的任务
                    }
                    recovered_count += 1
                    logger.info(f"恢复任务: {task_id} ({len(files)} 个文件)")
        
        if recovered_count > 0:
            save_tasks_state()  # 保存恢复的任务状态
            logger.info(f"成功恢复 {recovered_count} 个任务")
        
    except Exception as e:
        logger.error(f"恢复任务失败: {str(e)}")

# 初始化时加载任务状态
load_tasks_state()
recover_tasks_from_uploads()

# EDA分析结果字段中文映射
COLUMN_MAPPING = {
    # 基本信息
    'fileName': '文件名',
    'fileSize': '文件大小',
    'dataPoints': '数据点数',
    'duration': '记录时长(分钟)',
    'samplingRate': '采样率(Hz)',
    
    # 基本统计指标
    'meanEDA': '平均EDA(μS)',
    'stdEDA': 'EDA标准差(μS)',
    'minEDA': 'EDA最小值(μS)',
    'maxEDA': 'EDA最大值(μS)',
    'rangeEDA': 'EDA范围(μS)',
    'skewness': '偏度',
    'kurtosis': '峰度',
    
    # SCR峰值特征
    'scrPeaks': 'SCR峰值数量',
    'meanSCRAmplitude': '平均SCR幅度(μS)',
    'maxSCRAmplitude': '最大SCR幅度(μS)',
    'scrFrequency': 'SCR频率(次/分钟)',
    'meanSCRWidth': '平均SCR宽度(秒)',
    'meanSCRInterval': '平均SCR间隔(秒)',
    'stdSCRInterval': 'SCR间隔标准差(秒)',
    
    # SCL基线指标
    'baselineLevel': 'SCL基线水平(μS)',
    'baselineStd': 'SCL基线标准差(μS)',
    'baselineMin': 'SCL基线最小值(μS)',
    'baselineMax': 'SCL基线最大值(μS)',
    'baselineRange': 'SCL基线范围(μS)',
    
    # 频域分析
    'vlf_power': 'VLF功率',
    'lf_power': 'LF功率',
    'mf_power': 'MF功率',
    'total_power': '总功率',
    'vlf_ratio': 'VLF功率比(%)',
    'lf_ratio': 'LF功率比(%)',
    'mf_ratio': 'MF功率比(%)',
    'peak_freq': '主频(Hz)',
    
    # 信号质量
    'signalQuality': '信号质量',
    'snr': '信噪比',
    'artifactRatio': '伪影比例(%)',
    'validDataRatio': '有效数据比例(%)',
    
    # 其他可能的字段
    'processingTime': '处理时间(秒)',
    'analysisDate': '分析日期',
    'status': '分析状态'
}

def sanitize_numeric_value(value: Any) -> Any:
    """
    清理数值中的NaN和Infinity值，确保JSON序列化兼容性
    
    Args:
        value: 待清理的数值
        
    Returns:
        清理后的数值，NaN转为None，Infinity转为合理的边界值
    """
    if isinstance(value, (int, float)):
        if math.isnan(value):
            return None  # NaN转为None，在JSON中表示为null
        elif math.isinf(value):
            if value > 0:
                return 999999.0  # 正无穷转为大数值
            else:
                return -999999.0  # 负无穷转为小数值
    return value


def sanitize_analysis_result(result: Dict[str, Any]) -> Dict[str, Any]:
    """
    递归清理分析结果中的特殊数值
    
    Args:
        result: 分析结果字典
        
    Returns:
        清理后的结果字典
    """
    sanitized = {}
    for key, value in result.items():
        if isinstance(value, dict):
            sanitized[key] = sanitize_analysis_result(value)
        elif isinstance(value, list):
            sanitized[key] = [sanitize_numeric_value(item) for item in value]
        else:
            sanitized[key] = sanitize_numeric_value(value)
    return sanitized


def allowed_file(filename: str) -> bool:
    """检查文件扩展名是否允许"""
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


def validate_file_size(file: FileStorage) -> bool:
    """验证文件大小"""
    file.seek(0, 2)  # 移动到文件末尾
    size = file.tell()
    file.seek(0)  # 重置到文件开头
    return size <= MAX_FILE_SIZE


@eda_bp.route('/upload', methods=['POST'])
def upload_files():
    """
    文件上传接口
    支持单个或多个文件上传
    """
    try:
        logger.info("接收到EDA文件上传请求")
        
        # 检查是否有文件
        if 'files' not in request.files:
            return jsonify({'error': '没有找到文件字段'}), 400
        
        files = request.files.getlist('files')
        if not files or all(f.filename == '' for f in files):
            return jsonify({'error': '没有选择文件'}), 400
        
        # 生成任务ID
        task_id = str(uuid.uuid4())
        task_folder = UPLOAD_FOLDER / task_id
        task_folder.mkdir(exist_ok=True)
        
        uploaded_files = []
        
        for file in files:
            if file and file.filename != '':
                # 验证文件类型
                if not allowed_file(file.filename):
                    return jsonify({
                        'error': f'不支持的文件类型: {file.filename}。仅支持 .txt 和 .csv 文件'
                    }), 400
                
                # 验证文件大小
                if not validate_file_size(file):
                    return jsonify({
                        'error': f'文件 {file.filename} 超过最大限制 {MAX_FILE_SIZE // (1024*1024)}MB'
                    }), 400
                
                # 保存文件
                filename = secure_filename(file.filename)
                file_path = task_folder / filename
                file.save(str(file_path))
                
                # 获取文件信息
                file_size = file_path.stat().st_size
                
                uploaded_files.append({
                    'name': filename,
                    'size': file_size,
                    'path': str(file_path),
                    'status': 'uploaded'
                })
                
                logger.info(f"文件上传成功: {filename} ({file_size} bytes)")
        
        # 初始化任务状态
        analysis_tasks[task_id] = {
            'task_id': task_id,
            'status': 'uploaded',
            'files': uploaded_files,
            'created_at': datetime.now().isoformat(),
            'progress': 0,
            'results': [],
            'logs': []  # 添加日志存储
        }
        
        # 保存任务状态到文件
        save_tasks_state()
        
        return jsonify({
            'success': True,
            'task_id': task_id,
            'files': uploaded_files,
            'message': f'成功上传 {len(uploaded_files)} 个文件'
        })
        
    except Exception as e:
        logger.error(f"文件上传失败: {str(e)}")
        logger.error(traceback.format_exc())
        return jsonify({'error': f'文件上传失败: {str(e)}'}), 500


@eda_bp.route('/analyze', methods=['POST'])
def start_batch_analysis():
    """
    开始批量EDA分析 - 使用新的EDAProcessor
    """
    try:
        data = request.get_json()
        if not data:
            logger.error("请求数据为空")
            return jsonify({
                'success': False,
                'error': '请求数据不能为空',
                'message': '请求格式错误'
            }), 400
            
        task_id = data.get('task_id')
        config = data.get('config', {})
        
        logger.info(f"收到分析请求 - task_id: {task_id}, config: {config}")
        
        if not task_id:
            logger.error("任务ID为空")
            return jsonify({
                'success': False,
                'error': '任务ID不能为空',
                'message': '缺少必要参数'
            }), 400
            
        if task_id not in analysis_tasks:
            logger.error(f"任务ID不存在: {task_id}, 现有任务: {list(analysis_tasks.keys())}")
            return jsonify({
                'success': False,
                'error': f'任务ID不存在: {task_id}',
                'message': '任务不存在'
            }), 400
        
        task = analysis_tasks[task_id]
        if task['status'] == 'analyzing':
            return jsonify({
                'success': False,
                'error': '任务正在分析中',
                'message': '请等待当前分析完成'
            }), 400
        
        # 更新任务状态
        task['status'] = 'analyzing'
        task['progress'] = 0
        task['config'] = config
        task['started_at'] = datetime.now().isoformat()
        
        # 添加分析开始日志
        add_task_log(task_id, 'info', f'开始批量EDA分析，共{len(task["files"])}个文件')
        
        logger.info(f"开始EDA批量分析，任务ID: {task_id}")
        logger.info(f"分析配置: {config}")
        
        # 执行分析
        results = perform_batch_analysis(task_id, task['files'], config)
        
        # 更新任务状态
        task['status'] = 'completed'
        task['progress'] = 100
        task['results'] = results
        task['completed_at'] = datetime.now().isoformat()
        
        # 统计分析结果
        success_count = sum(1 for r in results if r.get('status') == 'completed')
        error_count = len(results) - success_count
        
        # 添加分析完成日志
        add_task_log(task_id, 'success', f'分析完成！成功: {success_count}个文件，失败: {error_count}个文件')
        
        # 保存任务状态到文件
        save_tasks_state()
        
        logger.info(f"EDA批量分析完成，任务ID: {task_id}, 成功: {success_count}, 失败: {error_count}")
        
        return jsonify({
            'success': True,
            'message': '分析完成',
            'task_id': task_id,
            'total_files': len(results),
            'success_count': success_count,
            'error_count': error_count,
            'results': results
        })
        
    except Exception as e:
        logger.error(f"批量分析失败: {str(e)}")
        logger.error(traceback.format_exc())
        
        # 更新任务状态为失败
        if 'task_id' in locals() and task_id in analysis_tasks:
            analysis_tasks[task_id]['status'] = 'failed'
            analysis_tasks[task_id]['error'] = str(e)
            analysis_tasks[task_id]['failed_at'] = datetime.now().isoformat()
            # 添加错误日志
            add_task_log(task_id, 'error', f'分析失败: {str(e)}')
            # 保存任务状态到文件
            save_tasks_state()
        
        return jsonify({
            'success': False,
            'error': f'分析失败: {str(e)}',
            'message': '分析过程中发生错误'
        }), 500


def add_task_log(task_id: str, log_type: str, message: str):
    """
    为任务添加日志记录
    
    Args:
        task_id: 任务ID
        log_type: 日志类型 (info, warning, error, success)
        message: 日志消息
    """
    if task_id in analysis_tasks:
        # 确保任务有logs字段
        if 'logs' not in analysis_tasks[task_id]:
            analysis_tasks[task_id]['logs'] = []
            
        timestamp = datetime.now().strftime('%H:%M:%S')
        log_entry = {
            'type': log_type,
            'message': message,
            'timestamp': timestamp
        }
        analysis_tasks[task_id]['logs'].append(log_entry)
        logger.info(f"[{task_id}] {log_type.upper()}: {message}")


def perform_batch_analysis(task_id: str, files: List[Dict], config: Dict) -> List[Dict]:
    """
    执行批量EDA分析 - 使用新的EDAProcessor
    
    Args:
        task_id: 任务ID
        files: 文件列表
        config: 分析配置
        
    Returns:
        分析结果列表
    """
    results = []
    
    # 获取分析配置
    sampling_rate = config.get('sampleRate', 4.0)
    algorithm = config.get('algorithm', 'brainhorm')  # 默认使用BrainHorm算法
    
    # 根据选择的算法创建不同的处理器配置
    if algorithm == 'neurokit2':
        # NeuroKit2算法配置 - 使用简化配置，依赖NeuroKit2库的默认参数
        processor_config = {
            'preprocessing': {
                'algorithm': 'neurokit2',
                'sampling_rate': float(sampling_rate)
            },
            'peak_detection': {
                'algorithm': 'neurokit2'
            },
            'quality_assessment': {
                'assessment_level': 'comprehensive'
            }
        }
    else:
        # BrainHorm算法配置 - 使用改进算法的详细配置
        processor_config = {
            'preprocessing': {
                'algorithm': 'improved',
                'outlier_threshold': 2.5,  # 固定阈值，不再依赖灵敏度
                'smooth_window': 1.0
            },
            'peak_detection': {
                'algorithm': 'improved',
                'min_amplitude': 0.01,
                'min_distance': 1.0
            },
            'quality_assessment': {
                'assessment_level': 'comprehensive'
            }
        }
    
    # 创建处理器实例
    processor = EDAProcessor(processor_config)
    
    total_files = len(files)
    
    for i, file_info in enumerate(files):
        try:
            logger.info(f"分析文件 {i+1}/{total_files}: {file_info['name']}")
            
            # 添加文件开始分析日志
            add_task_log(task_id, 'info', f'开始分析文件 ({i+1}/{total_files}): {file_info["name"]}')
            
            # 更新进度
            progress = int((i / total_files) * 100)
            analysis_tasks[task_id]['progress'] = progress
            
            # 加载EDA数据
            add_task_log(task_id, 'info', f'  正在加载数据文件...')
            try:
                # 首先尝试使用pandas读取CSV文件（自动处理标题行）
                if file_info['path'].lower().endswith('.csv'):
                    df = pd.read_csv(file_info['path'])
                    # 如果只有一列，直接使用
                    if len(df.columns) == 1:
                        eda_data = df.iloc[:, 0].values
                    else:
                        # 如果有多列，取最后一列作为EDA数据
                        eda_data = df.iloc[:, -1].values
                else:
                    # 对于txt文件，尝试跳过可能的标题行
                    try:
                        eda_data = np.loadtxt(file_info['path'])
                    except ValueError as e:
                        if "could not convert string" in str(e):
                            # 可能有标题行，跳过第一行
                            eda_data = np.loadtxt(file_info['path'], skiprows=1)
                        else:
                            raise e
                    
                    if eda_data.ndim > 1:
                        eda_data = eda_data[:, -1]  # 取最后一列作为EDA数据
                        
            except Exception as load_error:
                logger.error(f"数据加载失败: {load_error}")
                add_task_log(task_id, 'error', f'  数据加载失败: {str(load_error)}')
                raise load_error
            
            # 使用新的EDAProcessor进行分析
            add_task_log(task_id, 'info', f'  数据加载完成，开始预处理...')
            result = processor.process(eda_data, sampling_rate)
            
            # 提取分析结果
            peaks = result.get('peaks', {})
            metrics = result.get('metrics', {})
            quality = result.get('quality', {})
            
            # 添加分析步骤完成日志
            scr_count = int(metrics.get('scr_count', len(peaks.get('peak_indices', []))))
            quality_score = float(quality.get('overall_score', 0))
            add_task_log(task_id, 'info', f'  分析完成 - 检测到{scr_count}个SCR峰值，信号质量: {quality_score:.2f}')
            
            # 计算基本统计信息
            data_points = len(eda_data)
            duration = data_points / sampling_rate / 60  # 转换为分钟
            
            # 组装前端需要的结果格式
            analysis_result = {
                'fileName': file_info['name'],
                'fileSize': file_info['size'],
                'dataPoints': data_points,
                'duration': float(duration),
                'samplingRate': sampling_rate,
                
                # 基本统计 - 直接使用EDA处理器返回的metrics
                'meanEDA': float(metrics.get('mean_eda', 0)),
                'stdEDA': float(metrics.get('std_eda', 0)),
                'minEDA': float(metrics.get('min_eda', 0)),
                'maxEDA': float(metrics.get('max_eda', 0)),
                'rangeEDA': float(metrics.get('range_eda', 0)),
                'skewness': float(metrics.get('complexity_features', {}).get('skewness', 0)),
                'kurtosis': float(metrics.get('complexity_features', {}).get('kurtosis', 0)),
                
                # SCR特征
                'scrPeaks': int(metrics.get('scr_count', len(peaks.get('peak_indices', [])))),
                'meanSCRAmplitude': float(metrics.get('scr_amplitude_mean', np.mean(peaks.get('peak_amplitudes', [0])))),
                'maxSCRAmplitude': float(metrics.get('scr_amplitude_max', np.max(peaks.get('peak_amplitudes', [0])) if peaks.get('peak_amplitudes') else 0)),
                'scrFrequency': float(metrics.get('scr_rate', 0)),
                'meanSCRWidth': float(metrics.get('scr_width_mean', 0)),
                
                # SCL基线 - 使用EDA处理器的基线指标
                'baselineLevel': float(metrics.get('scl_mean', metrics.get('mean_eda', 0))),
                'baselineStd': float(metrics.get('scl_std', metrics.get('std_eda', 0))),
                'trendSlope': float(metrics.get('scl_slope', 0)),
                
                # 信号质量
                'signalQuality': float(quality.get('overall_score', 0)),
                'snrDB': float(quality.get('snr_db', 0)),
                'zeroRatio': float((1 - quality.get('completeness', 1)) * 100),
                'stabilityIndex': float(quality.get('stability', 0)),
                
                # 频域特征
                'vlf_power': float(metrics.get('frequency_features', {}).get('vlf_power', 0)),
                'lf_power': float(metrics.get('frequency_features', {}).get('lf_power', 0)),
                'mf_power': float(metrics.get('frequency_features', {}).get('mf_power', 0)),
                'total_power': float(metrics.get('frequency_features', {}).get('total_power', 0)),
                'vlf_ratio': float(metrics.get('frequency_features', {}).get('vlf_ratio', 0) * 100),
                'lf_ratio': float(metrics.get('frequency_features', {}).get('lf_ratio', 0) * 100),
                'mf_ratio': float(metrics.get('frequency_features', {}).get('mf_ratio', 0) * 100),
                'peak_freq': float(metrics.get('frequency_features', {}).get('peak_frequency', 0)),
                
                # 分析时间戳
                'analyzedAt': datetime.now().isoformat(),
                'status': 'completed'
            }
            
            # 清理特殊数值，确保JSON序列化兼容性
            analysis_result = sanitize_analysis_result(analysis_result)
            
            results.append(analysis_result)
            add_task_log(task_id, 'success', f'  文件 {file_info["name"]} 分析成功')
            logger.info(f"文件 {file_info['name']} 分析完成")
            
        except Exception as e:
            logger.error(f"分析文件 {file_info['name']} 失败: {str(e)}")
            logger.error(traceback.format_exc())
            
            # 添加文件分析失败日志
            add_task_log(task_id, 'error', f'  文件 {file_info["name"]} 分析失败: {str(e)}')
            
            # 添加错误结果
            error_result = {
                'fileName': file_info['name'],
                'fileSize': file_info['size'],
                'status': 'error',
                'error': str(e),
                'analyzedAt': datetime.now().isoformat()
            }
            results.append(error_result)
    
    return results


@eda_bp.route('/task/<task_id>/logs', methods=['GET'])
def get_task_logs(task_id: str):
    """
    获取任务的实时日志
    """
    try:
        if task_id not in analysis_tasks:
            return jsonify({'error': '任务不存在'}), 404
        
        task = analysis_tasks[task_id]
        logs = task.get('logs', [])
        
        return jsonify({
            'success': True,
            'task_id': task_id,
            'logs': logs,
            'total_logs': len(logs)
        })
        
    except Exception as e:
        logger.error(f"获取任务日志失败: {str(e)}")
        return jsonify({'error': f'获取日志失败: {str(e)}'}), 500


@eda_bp.route('/task/<task_id>/status', methods=['GET'])
def get_task_status(task_id: str):
    """
    获取任务状态
    """
    try:
        if task_id not in analysis_tasks:
            return jsonify({'error': '任务不存在'}), 404
        
        task = analysis_tasks[task_id]
        return jsonify({
            'success': True,
            'task': task
        })
        
    except Exception as e:
        logger.error(f"获取任务状态失败: {str(e)}")
        return jsonify({'error': f'获取任务状态失败: {str(e)}'}), 500


@eda_bp.route('/task/<task_id>/results', methods=['GET'])
def get_analysis_results(task_id: str):
    """
    获取分析结果
    """
    try:
        if task_id not in analysis_tasks:
            return jsonify({'error': '任务不存在'}), 404
        
        task = analysis_tasks[task_id]
        if task['status'] != 'completed':
            return jsonify({'error': '分析尚未完成'}), 400
        
        return jsonify({
            'success': True,
            'results': task['results'],
            'task_info': {
                'task_id': task_id,
                'status': task['status'],
                'created_at': task['created_at'],
                'completed_at': task.get('completed_at'),
                'file_count': len(task['files'])
            }
        })
        
    except Exception as e:
        logger.error(f"获取分析结果失败: {str(e)}")
        return jsonify({'error': f'获取分析结果失败: {str(e)}'}), 500


@eda_bp.route('/export/<task_id>/<format>', methods=['GET'])
def export_results(task_id: str, format: str):
    """
    导出分析结果
    支持CSV和Excel格式
    """
    try:
        if task_id not in analysis_tasks:
            return jsonify({'error': '任务不存在'}), 404
        
        task = analysis_tasks[task_id]
        if task['status'] != 'completed':
            return jsonify({'error': '分析尚未完成'}), 400
        
        results = task['results']
        if not results:
            return jsonify({'error': '没有可导出的结果'}), 400
        
        # 创建DataFrame
        df = pd.DataFrame(results)
        
        # 将列名替换为中文表头
        chinese_columns = {}
        for col in df.columns:
            if col in COLUMN_MAPPING:
                chinese_columns[col] = COLUMN_MAPPING[col]
            else:
                # 如果没有映射，保持原列名
                chinese_columns[col] = col
                logger.warning(f"未找到字段 '{col}' 的中文映射，保持原名")
        
        df = df.rename(columns=chinese_columns)
        
        # 生成文件名
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        
        if format.lower() == 'csv':
            filename = f'EDA分析结果_{timestamp}.csv'
            filepath = OUTPUT_FOLDER / filename
            df.to_csv(filepath, index=False, encoding='utf-8-sig')
            
        elif format.lower() == 'excel':
            filename = f'EDA分析结果_{timestamp}.xlsx'
            filepath = OUTPUT_FOLDER / filename
            df.to_excel(filepath, index=False, engine='openpyxl')
            
        else:
            return jsonify({'error': '不支持的导出格式'}), 400
        
        logger.info(f"导出结果文件: {filename}")
        
        return send_file(
            filepath,
            as_attachment=True,
            download_name=filename,
            mimetype='application/octet-stream'
        )
        
    except Exception as e:
        logger.error(f"导出结果失败: {str(e)}")
        logger.error(traceback.format_exc())
        return jsonify({'error': f'导出失败: {str(e)}'}), 500


@eda_bp.route('/task/<task_id>/delete', methods=['DELETE'])
def delete_task(task_id: str):
    """
    删除任务和相关文件
    """
    try:
        if task_id not in analysis_tasks:
            return jsonify({'error': '任务不存在'}), 404
        
        # 删除上传的文件
        task_folder = UPLOAD_FOLDER / task_id
        if task_folder.exists():
            import shutil
            shutil.rmtree(task_folder)
        
        # 删除任务记录
        del analysis_tasks[task_id]
        
        # 保存任务状态到文件
        save_tasks_state()
        
        logger.info(f"任务 {task_id} 已删除")
        
        return jsonify({
            'success': True,
            'message': '任务已删除'
        })
        
    except Exception as e:
        logger.error(f"删除任务失败: {str(e)}")
        return jsonify({'error': f'删除任务失败: {str(e)}'}), 500


@eda_bp.route('/tasks', methods=['GET'])
def list_tasks():
    """
    获取所有任务列表
    """
    try:
        tasks = []
        for task_id, task in analysis_tasks.items():
            task_summary = {
                'task_id': task_id,
                'status': task['status'],
                'file_count': len(task['files']),
                'created_at': task['created_at'],
                'progress': task.get('progress', 0)
            }
            
            if 'completed_at' in task:
                task_summary['completed_at'] = task['completed_at']
            
            if 'error' in task:
                task_summary['error'] = task['error']
                
            tasks.append(task_summary)
        
        return jsonify({
            'success': True,
            'tasks': tasks
        })
        
    except Exception as e:
        logger.error(f"获取任务列表失败: {str(e)}")
        return jsonify({'error': f'获取任务列表失败: {str(e)}'}), 500


@eda_bp.errorhandler(413)
def too_large(e):
    """处理文件过大错误"""
    return jsonify({'error': '文件过大，请上传小于50MB的文件'}), 413


@eda_bp.errorhandler(500)
def internal_error(e):
    """处理内部服务器错误"""
    logger.error(f"内部服务器错误: {str(e)}")
    return jsonify({'error': '内部服务器错误'}), 500